package thread

import (
	"codejy/globalfunc"
	"codejy/store"
	"codejy/structdef"
	"codejy/typedefault"
	"codejy/utils"
	"os"
	"strconv"
)

type ThreadPool struct {
	Addr        string
	ThreadStore *structdef.ThreadStore
	Pool        *utils.GorotinesPool //线程池
}

// 创建实例
func (a *ThreadPool) CreateTypeDefault(addr string, threadStore *structdef.ThreadStore, parameter ...string) {
	s := parameter[0]
	if s == `""` {
		panic("ThreadPool第一个参数错误,不能为空,并且是整数,表示线程池最大线程数")
	}
	maxSize, p := strconv.Atoi(s)
	if p != nil {
		panic("ThreadPool第一个参数错误,必须是整数,表示线程池最大线程大小")
	}
	s1 := parameter[1]
	if s1 == `""` {
		panic("ThreadPool第二个参数错误,不能为空,并且是整数,表示线程池最小线程数")
	}
	minSize, p := strconv.Atoi(s1)
	if p != nil {
		panic("ThreadPool第二个参数错误,必须是整数,表示线程池最小线程大小")
	}
	s2 := parameter[2]
	if s2 == `""` {
		panic("ThreadPool第三个参数错误,不能为空,并且是整数,表示线程池最大任务数")
	}
	maxTask, p := strconv.Atoi(s2)
	if p != nil {
		panic("ThreadPool第三个参数错误,必须是整数,表示线程池最大任务数")
	}
	s3 := parameter[3]
	if s3 == `""` {
		panic("ThreadPool第四个参数错误,不能为空,并且是整数,任务超时时间，单位s")
	}
	timeout, p := strconv.Atoi(s3)
	if p != nil {
		panic("ThreadPool第四个参数错误,必须是整数,任务超时时间，单位s")
	}
	pool := utils.GetPool(maxSize, minSize, maxTask, timeout)
	instance := &ThreadPool{
		Addr:        addr,
		ThreadStore: threadStore,
		Pool:        pool,
	}
	store.AddTypeDefaultInstanceStore(threadStore, a.GetTypeName(), addr, instance)
}
func (a *ThreadPool) ParameterProcessing(parameter []string) []string {
	return parameter
}

func (a *ThreadPool) GetData() interface{} {
	return a.Pool
}

func (a *ThreadPool) ToStr() string {
	return ""
}

// 执行任务
func (a *ThreadPool) ExecuteTask(parameter string) {
	funcArgs, b := typedefault.GetTypeDefaultValue[[]string](a.ThreadStore, "List", parameter)
	if !b {
		panic("错误::::::参数错误")
	}
	var funName = funcArgs[0]
	if funName == `""` {
		panic("错误::::::参数错误,第一个参数不能为空")
	}
	//去掉"
	funName = funName[1 : len(funName)-1]
	//获取函数定义,函数定义是在当前文件中定义的
	definition := store.SearchFunDefinition(a.ThreadStore, funName)
	if definition == nil {
		panic("错误::::::函数未定义:" + funName)
	}
	var funArgs = funcArgs[1:]
	//创建线程,的子线程环境
	newThreadId, newThreadStore := store.CopyThread(a.ThreadStore, definition.Body, 0, definition.Name)
	ThreadAllWait.Add(1) //添加一个线程
	err := a.Pool.Execute(func() {
		defer func() {
			if err := recover(); err != nil {
				//删除线程里产生的变量
				store.DeleteThreadStore(newThreadId)
				store.PrintExecuteCodeRecordLog(newThreadStore, err)
				os.Exit(1)
			}
		}()
		globalfunc.ExecuteFunc("FunLineExecute", newThreadStore, definition.Body, "", definition.Name, funArgs)
		//如果线程没有被停止,并且线程没有等待,就删除线程里产生的变量,和线程环境
		//线程执行完毕,删除线程里产生的变量,和线程环境
		store.DeleteThreadStore(newThreadId)
		//线程执行完毕后,打印线程执行过程
		if utils.Debug {
			store.PrintExecuteCodeRecordLog(newThreadStore, nil)
		}
		ThreadAllWait.Done()
	})
	if err != nil {
		panic(err)
	}
}

// 结束线程池
func (a *ThreadPool) Close() {
	a.Pool.Close()
}

// 结束线程池,并且等待所有任务完成
func (a *ThreadPool) Wait() {
	a.Pool.Wait()
}

func (f *ThreadPool) GetDef() string {
	return `
		@CodeManual(def="new("ThreadPool","线程池参数...")",des="创建线程池,具体参数传递可以使用-doc ThreadPool查看文档")
		type ThreadPool{
			//$maxSize:线程池最大线程数   ,当最小线程数都在执行任务时,会创建新的线程,直到最大线程数,超出最大线程数会阻塞,直到有空闲线程
			//$minSize:线程池最小线程数   ,始终保持的线程数,就算没有任务也不会释放线程
			//$maxTask:线程池最大任务数   ,超出任务数会阻塞,直到有空闲线程
			//$timeout:任务超时时间，单位s, 建议设置稍微大一点,比如任务执行时间为1s,那么timeout设置为3s~5s
			def init{
				core&CreateTypeDefault($maxSize,$minSize,$maxTask,$timeout)
			}
			@CodeManual(def="runTask($realArgs)",des="运行任务,第一个参数必须是函数名,后面的参数是函数的参数")
			def runTask{
				core&ExecuteTask($realArgs)
			}
			@CodeManual(def="close()",des="结束线程池")
			def close{
				core&Close()
			}
			@CodeManual(def="wait()",des="结束线程池,并且等待所有任务完成")
			def wait{
				core&Wait()
			}

		
		}
	`
}
func init() {
	typedefault.RegisterTypeDefault(&ThreadPool{})
}

func (f *ThreadPool) GetTypeName() string {
	return "ThreadPool"
}
